package com.zy.design.pattern.di;

import cn.hutool.core.collection.CollectionUtil;
import com.zy.design.pattern.di.meat.ClassMeat;
import com.zy.design.pattern.di.meat.ConstructorArgs;
import com.zy.design.pattern.di.meat.MeatParse;
import com.zy.design.pattern.di.meat.Scope;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zhaoyi
 * @date 2021/4/1 11:13
 */
public class BeanFactory {


    //单例的放这里
    private static final Map<String, Object> map = new ConcurrentHashMap<>();

    //元信息
    private static final Map<String, ClassMeat> mateMap = new HashMap<>();

    //非懒加载的单例对象初始化--简单工厂
    static {
        try {
            for (ClassMeat r : MeatParse.parse().values()) {
                mateMap.put(r.getId(), r);
                if (!r.isLazy() && r.getScope().equals(Scope.singleton)) {
                    System.out.println("单例非懒加载初始化 " + r.getId());
                    try {
                        Object bean = createBean(r);
                        map.putIfAbsent(r.getId(), bean);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    private static Object createBean(ClassMeat classMeat) throws IllegalAccessException,
            InstantiationException, NoSuchMethodException, InvocationTargetException {

        Object obj = map.get(classMeat.getId());
        if (obj != null) {
            return obj;
        }

        Class<?> aClass = classMeat.getClazzName();
        //无参数的类
        if (CollectionUtil.isEmpty(classMeat.getConstructorArgsList())) {
            if (classMeat.getScope().equals(Scope.singleton)) {
                return aClass.newInstance();
            }
        }
        List<ConstructorArgs> constructorArgsList = classMeat.getConstructorArgsList();
        Class[] argClasses = new Class[constructorArgsList.size()];
        Object[] objs = new Object[constructorArgsList.size()];
        //解析构造参数
        for (int i = 0; i < constructorArgsList.size(); i++) {
            ConstructorArgs constructorArgs = constructorArgsList.get(i);
            if (constructorArgs.isHasRef()) {
                argClasses[i] = constructorArgs.getType();
                Object bean = map.get((String) constructorArgs.getValue());
                if (bean == null) {
                    ClassMeat attrMeat = mateMap.get((String) constructorArgs.getValue());
                    bean = createBean(attrMeat);
                    if (attrMeat.getScope().equals(Scope.singleton)) {
                        map.put(attrMeat.getId(), bean);
                    }

                }
                objs[i] = bean;
            } else {
                argClasses[i] = constructorArgs.getType();
                objs[i] = constructorArgs.getValue();
            }
        }
        Object o = aClass.getDeclaredConstructor(argClasses).newInstance(objs);
        if (classMeat.getScope().equals(Scope.singleton)) {
            map.put(classMeat.getId(), o);
        }
        return o;
    }

    public static Object getBean(String beanId) {
        ClassMeat classMeat = mateMap.get(beanId);
        try {
            return createBean(classMeat);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
